package ca.mcgill.mni.bic;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;

import org.apache.log4j.Logger;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

/**
 * @author jharlap
 * 
 */
public class StudyInfoWidget extends Composite {
	
	static Logger logger = Logger.getLogger(StudyInfoWidget.class);

	private Text patientNameField, patientIdField, patientSexField,
	// studyDescriptionField,
			patientDoBField;

	private Label studyUIDField, studyDateField;

	private Button saveButton, sendButton;

	private Color red;

	private Study study;

	private Shell shell;

	public StudyInfoWidget(Composite parent, int style) {
		super(parent, style);

		shell = parent.getShell();

		red = shell.getDisplay().getSystemColor(SWT.COLOR_RED);

		Group group = new Group(this, SWT.BORDER);
		group.setText("Study info");

		Label patientNameLabel = new Label(group, SWT.NONE);
		patientNameLabel.setText("Patient Name:");

		patientNameField = new Text(group, SWT.SINGLE);
		patientNameField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

		patientNameField.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent event) {
				if (Study.isValidPatientName(patientNameField.getText())) {
					patientNameField.setForeground(null);
				} else {
					patientNameField.setForeground(red);
				}
			}
		});

		Label patientIdLabel = new Label(group, SWT.NONE);
		patientIdLabel.setText("Patient ID:");

		patientIdField = new Text(group, SWT.SINGLE);
		patientIdField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

		Label patientSexLabel = new Label(group, SWT.NONE);
		patientSexLabel.setText("Patient Sex:");

		patientSexField = new Text(group, SWT.SINGLE);
		patientSexField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

		Label patientDoBLabel = new Label(group, SWT.NONE);
		patientDoBLabel.setText("Patient DoB:");

		patientDoBField = new Text(group, SWT.SINGLE);
		patientDoBField.setTextLimit(10);
		patientDoBField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

		// Label studyDescriptionLabel = new Label(group, SWT.NONE);
		// studyDescriptionLabel.setText("Study Description:");
		//		
		// studyDescriptionField = new Text(group, SWT.SINGLE);
		// studyDescriptionField.setLayoutData(new
		// GridData(GridData.FILL_HORIZONTAL));

		Label studyUIDLabel = new Label(group, SWT.NONE);
		studyUIDLabel.setText("Study UID:");

		studyUIDField = new Label(group, SWT.SINGLE);
		studyUIDField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

		Label studyDateLabel = new Label(group, SWT.NONE);
		studyDateLabel.setText("Study Date:");

		studyDateField = new Label(group, SWT.SINGLE);
		studyDateField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

		// the buttons area
		Group buttons = new Group(this, SWT.BORDER);
		buttons.setText("Study operations");

		// the save button
		saveButton = new Button(buttons, SWT.PUSH);
		saveButton.setText("Save Changes");

		saveButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				updateHeaders();
			}
		});
		saveButton.setEnabled(false);

		ModifyListener enableSaveButton = new ModifyListener() {
			public void modifyText(ModifyEvent event) {
				saveButton.setEnabled(canSave());
			}
		};

		patientNameField.addModifyListener(enableSaveButton);
		patientIdField.addModifyListener(enableSaveButton);
		patientSexField.addModifyListener(enableSaveButton);
		patientDoBField.addModifyListener(enableSaveButton);
		// studyDescriptionField.addModifyListener(enableSaveButton);

		// the delete button
		Button deleteButton = new Button(buttons, SWT.PUSH);
		deleteButton.setText("Delete Study");

		deleteButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				deleteStudy();
			}
		});

		// the send button
		sendButton = new Button(buttons, SWT.PUSH);
		sendButton.setText("Send Study");

		sendButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				sendStudy();
			}
		});

		/*
		 * ModifyListener enableSendButton = new ModifyListener() { public void
		 * modifyText(ModifyEvent event) { sendButton
		 * .setEnabled(patientNameField != null &&
		 * Study.isValidPatientName(patientNameField .getText())); } };
		 */

		buttons.setLayout(new RowLayout(SWT.HORIZONTAL));

		setLayout(new RowLayout(SWT.VERTICAL));

		GridLayout gridLayout = new GridLayout();
		gridLayout.numColumns = 2;
		group.setLayout(gridLayout);

	}

	public void setStudy(Study study) {
		this.study = study;

		if (study.patientName != null)
			patientNameField.setText(study.patientName);

		if (study.patientID != null)
			patientIdField.setText(study.patientID);

		if (study.patientSex != null)
			patientSexField.setText(study.patientSex);

		if (study.patientDoB != null)
			patientDoBField.setText(study.patientDoB.toString());

		// if(study.studyDescription != null)
		// studyDescriptionField.setText(study.studyDescription);

		if (study.studyUID != null)
			studyUIDField.setText(study.studyUID);

		if (study.studyDate != null)
			studyDateField.setText(study.studyDate.toString());
	}

	private boolean canSave() {
		if (study == null)
			return false;

		if (!patientNameField.getText().equalsIgnoreCase(study.patientName)) {
			return true;
		}

		if (!patientIdField.getText().equalsIgnoreCase(study.patientID)) {
			return true;
		}

		if ((study.patientDoB != null && !patientDoBField.getText()
				.equalsIgnoreCase(study.patientDoB.toString()))
				|| (study.patientDoB == null && !patientDoBField.getText()
						.equals(""))) {
			return true;
		}

		if (!patientSexField.getText().equalsIgnoreCase(study.patientSex)) {
			return true;
		}

		/*
		 * if(!(study.studyDescription == null &&
		 * studyDescriptionField.getText() == null) &&
		 * !studyDescriptionField.getText().equalsIgnoreCase(study.studyDescription)) {
		 * System.out.println("sdesc '" + studyDescriptionField.getText() + "' '" +
		 * study.studyDescription + "'"); return true; }
		 */

		return false;
	}

	private void deleteStudy() {
		String realPatientName = this.patientNameField.getText();
		String deleteMessage = "Deleting a study cannot be undone.\nTo confirm that you want to delete this study,\nplease enter the patient name\n'"
				+ realPatientName
				+ "'\n below (without the quotes).\nOtherwise, click Cancel.";
		InputDialog input = new InputDialog(shell);
		String patientName = input.open(deleteMessage);

		// null if Cancel selected
		if (patientName == null)
			return;

		// Let them keep trying until they get it right
		deleteMessage = "The entered name does not match this study.\n\n"
				+ deleteMessage;
		while (patientName != null
				&& !patientName.equalsIgnoreCase(realPatientName)) {
			input = new InputDialog(shell);
			patientName = input.open(deleteMessage);

			// null if Cancel selected
			if (patientName == null)
				return;
		}

		// they got it right... so delete.
		Runtime runtime = Runtime.getRuntime();
		String[] command = { "deleteStudy.pl", study.tarchiveID.toString() };
		logger.info("Deleting study: " + Arrays.toString(command));
		
		ProgressDialog progress = new ProgressDialog(shell, SWT.INDETERMINATE);

		try {

			boolean done = false;
			int exitValue = 0;
			progress.open("Deleting study, please wait.");
			Process proc = runtime.exec(command);

			while (!done) {
				try {
					exitValue = proc.exitValue();
					done = true;
				} catch (IllegalThreadStateException e) {
					progress.update();
				}
			}

			if (exitValue != 0) {
				MessageBox warn = new MessageBox(shell);
				logger.info("Deletion failure - exit code " + exitValue);
				warn.setText("Error");
				warn
						.setMessage("Study deletion had an error.  Please contact support.");
				warn.open();
			}

		} catch (IOException e) {
			MessageBox warn = new MessageBox(shell);
			logger.info("Deletion failure - error: " + e.getMessage());
			warn.setText("Error");
			warn
					.setMessage("Could not delete the study.  Please contact support.\n"
							+ e.getMessage());
			warn.open();
		}

		progress.close();
		logger.debug("Deletion complete");
	}

	private void updateHeaders() {
		Runtime runtime = Runtime.getRuntime();
		String[] command = { "updateHeaders.pl", study.getPath(), "-verbose", "-database", "-profile", "ibis", "-set",
				"PatientsName", patientNameField.getText(), "-set",
				"PatientID", patientIdField.getText(), "-set", "PatientsSex",
				patientSexField.getText(), "-set", "PatientsBirthDate",
				patientDoBField.getText().replaceAll("-", "") };

		logger.info("Updating headers for tarchiveID " + study.tarchiveID);
		logger.debug("Running: " + Arrays.toString(command));
		ProgressDialog progress = new ProgressDialog(shell, SWT.INDETERMINATE);

		try {

			boolean done = false;
			int exitValue = 0;
			progress
					.open("Updating headers, please wait. (This can take\na while, you might want to get some coffee...)");
			Process proc = runtime.exec(command, null, null);
			BufferedReader procError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
			BufferedReader procOutput = new BufferedReader(new InputStreamReader(proc.getInputStream()));

			while (!done) {
				String outLine, errLine;
				if(procOutput.ready()) {
					outLine = procOutput.readLine();
					System.out.println(outLine);
					logger.debug(outLine);
				}
				
				if(procError.ready()) {
					errLine = procError.readLine();
					System.out.println(errLine);
					logger.debug(errLine);
				}
				try {
					exitValue = proc.exitValue();
					done = true;
				} catch (IllegalThreadStateException e) {
					progress.update();
				}
			}

			if (exitValue != 0) {
				logger.info("Update failure - exit code " + exitValue);
				MessageBox warn = new MessageBox(shell);
				warn.setText("Error");
				warn
						.setMessage("Header update had an error.  Please contact support.");
				warn.open();
			}

		} catch (IOException e) {
			logger.info("Update failure - message: " + e.getMessage());
			MessageBox warn = new MessageBox(shell);
			warn.setText("Error");
			warn
					.setMessage("Could not update headers.  Please contact support.\n"
							+ e.getMessage());
			warn.open();
		}

		progress.close();
		logger.debug("Update complete");
	}

	private void sendStudy() {
		logger.info("Send requested for tarchiveID " + study.tarchiveID);
		
		// do not transfer if the patient name is invalid
		if (!Study.isValidPatientName(study.patientName)) {
			logger.debug("Send refused for invalid name (" + study.patientName + ")");
			MessageBox warn = new MessageBox(shell, SWT.ICON_ERROR);
			warn.setText("Invalid Patient Name");
			warn
					.setMessage("The patient name does not conform to naming procedures, and so will not be transferred.  Please relabel before trying again.");
			warn.open();
			return;
		}

		// check for invalid series descriptions
		boolean allSeriesDescriptionsValid = true;
		for (Series series : study.series) {
			if (!Series.isValidDescription(series.seriesDescription)) {
				allSeriesDescriptionsValid = false;
			}
		}

		// warn the user if any series descriptions are invalid
		if (!allSeriesDescriptionsValid) {
			int selectedChoice;
			MessageBox warn = new MessageBox(shell, SWT.ICON_QUESTION | SWT.YES
					| SWT.NO);
			warn.setText("Invalid Series Descriptions");
			warn
					.setMessage("One or more series do not conform to labelling procedures.  Are you sure you want to transfer this study?  Choose No if you want to relabel the series.");
			selectedChoice = warn.open();
			if (selectedChoice == SWT.NO) {
				logger.info("Send cancelled by user for mislabelled series");
				return;
			}
		}

		// schedule the transfer
		Runtime runtime = Runtime.getRuntime();
		String[] command = { "sendStudy.pl", study.tarchiveID.toString() };
		logger.debug("Running: " + Arrays.toString(command));
		
		ProgressDialog progress = new ProgressDialog(shell, SWT.INDETERMINATE);

		try {

			boolean done = false;
			int exitValue = 0;
			progress.open("Scheduling transfer, please wait.");
			Process proc = runtime.exec(command);

			while (!done) {
				try {
					exitValue = proc.exitValue();
					done = true;
				} catch (IllegalThreadStateException e) {
					progress.update();
				}
			}

			if (exitValue != 0) {
				logger.info("Send failure - exit code " + exitValue);
				MessageBox warn = new MessageBox(shell);
				warn.setText("Error");
				warn
						.setMessage("Transfer scheduler had an error.  Please contact support.");
				warn.open();
			}

		} catch (IOException e) {
			logger.info("Send failure - error message: " + e.getMessage());
			MessageBox warn = new MessageBox(shell);
			warn.setText("Error");
			warn
					.setMessage("Could not schedule transfer.  Please contact support.\n"
							+ e.getMessage());
			warn.open();
		}

		progress.close();
		logger.debug("Send complete");
	}

} // end StudyInfoWidget
